/*
 * Copyright (C) 2011 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.bkkit.redlung;

import java.io.File;
import java.util.HashMap;
import java.util.Set;

import org.bukkit.entity.Player;
import org.bukkit.util.config.Configuration;

public class RadiatedPlayers {
	private static final String SOURCE_CLASS = RadiatedPlayers.class.getName();
	private final HashMap<Player, RadiationAccumulator> sickPlayers = new HashMap<Player, RadiationAccumulator>();
	private final Configuration sickPlayersPersistence;
	private final Config config;

	public RadiatedPlayers(Config config, final File datafile) {
		super();
		this.sickPlayersPersistence = new Configuration(datafile);
		this.config = config;
	}

	synchronized void enable() {
		LogWrapper.entering(SOURCE_CLASS, "init", null);
		this.sickPlayersPersistence.load();
		LogWrapper.exiting(SOURCE_CLASS, "init", null);
	}

	synchronized void disable() {
		LogWrapper.entering(SOURCE_CLASS, "disable", null);
		Set<Player> sickPlayers = this.sickPlayers.keySet();
		for (Player player : sickPlayers) {
			RadiationAccumulator radiationAccumulator = this.sickPlayers
					.get(player);
			if ((radiationAccumulator != null)
					&& (radiationAccumulator.getAccumulatedRadiation() > 0)) {
				LogWrapper.fine(player.getName() + " has accumulated "
						+ radiationAccumulator.getAccumulatedRadiation());
				this.sickPlayersPersistence.setProperty(player.getName(),
						radiationAccumulator.getAccumulatedRadiation());
			}
		}
		this.sickPlayersPersistence.save();
		LogWrapper.exiting(SOURCE_CLASS, "disable", null);
	}

	synchronized HashMap<Player, RadiationAccumulator> getSickPlayers() {
		return new HashMap<Player, RadiationAccumulator>(this.sickPlayers);
	}

	synchronized void playerJoin(final Player player) {
		LogWrapper.entering(SOURCE_CLASS, "loadPlayer", player);
		if (!this.sickPlayers.containsKey(player)) {
			LogWrapper
					.fine("Player does not have an in-memory counter, load from persistence");
			int accumulatedRadiation = this.sickPlayersPersistence.getInt(
					player.getName(), 0);
			if (accumulatedRadiation > 0) {
				setRadiationLevel(player, accumulatedRadiation);
			}
		}
		LogWrapper.exiting(SOURCE_CLASS, "loadPlayer", player);
	}

	synchronized void radiatePlayer(final Player player) {
		LogWrapper.entering(SOURCE_CLASS, "radiatePlayer", player);
		RadiationAccumulator radiationAccumulator = getAccumulator(player);
		radiationAccumulator.addRadiation(this.config.getRadiationStrength());
		LogWrapper.exiting(SOURCE_CLASS, "radiatePlayer", player);
	}

	synchronized void setRadiationLevel(final Player player, final int dosage) {
		LogWrapper.entering(SOURCE_CLASS, "setRadiationLevel", player);
		RadiationAccumulator radiationAccumulator = getAccumulator(player);
		radiationAccumulator.setAccumulatedRadiation(dosage);
		checkCure(player);
		LogWrapper.exiting(SOURCE_CLASS, "setRadiationLevel", player);
	}

	void heal(Player player, int strength) {
		LogWrapper.entering(SOURCE_CLASS, "heal", player);
		RadiationAccumulator radiationAccumulator = getAccumulator(player);
		radiationAccumulator.removeRadiation(strength);
		checkCure(player);
		LogWrapper.exiting(SOURCE_CLASS, "heal", player);

	}

	synchronized int getAccumulatedAmount(final Player player) {
		RadiationAccumulator radiationAccumulator = this.sickPlayers
				.get(player);
		return (radiationAccumulator == null) ? 0 : radiationAccumulator
				.getAccumulatedRadiation();
	}

	private synchronized RadiationAccumulator getAccumulator(final Player player) {
		LogWrapper.entering(SOURCE_CLASS, "getAccumulator", player);
		RadiationAccumulator radiationAccumulator = this.sickPlayers
				.get(player);
		if (radiationAccumulator == null) {
			LogWrapper.fine(player.getName() + " gets a new accumulator");
			radiationAccumulator = new RadiationAccumulator();
			this.sickPlayers.put(player, radiationAccumulator);
		}
		LogWrapper.exiting(SOURCE_CLASS, "getAccumulator", player);
		return radiationAccumulator;
	}

	private void checkCure(final Player player) {
		if (getAccumulatedAmount(player) < 1) {
			LogWrapper.fine(player.getName() + " was cured of radiation");
			player.sendMessage(this.config.getCuredMessage());
			if (this.sickPlayers.get(player) != null) {
				this.sickPlayers.remove(player);
				this.sickPlayersPersistence.removeProperty(player.getName());
			}
		}
	}
}
